/*
 * Copyright 2011 The Apache Software Foundation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package fr.gaellalire.jzip.actions;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import fr.gaellalire.jzip.Parameters;

/**
 *
 * @author Gael Lalire
 */
public class FileListCompressAction extends AbstractCompressAction {

    private List<File> sources;

    public FileListCompressAction(final List<File> sources) {
        this.sources = sources;
    }

    public int addFileInArchive(final File file, final String prefix, final List<FutureEntry> futureEntries) throws IOException {
        if (file.isDirectory()) {
            File[] children = file.listFiles();
            int total = 0;
            for (File child : children) {
                total += addFileInArchive(child, prefix + file.getName() + "/", futureEntries);
            }
            if (total == 0) {
                // empty dir
                futureEntries.add(new FutureEntry(prefix + file.getName() + "/", 0, null));
                total++;
            }
            return total;
        } else {
            if (file.getName().matches(Parameters.getIgnoredFilesForCompression())) {
                return 0;
            }
            futureEntries.add(new FutureEntry(prefix + file.getName(), file.length(), new FileInputStream(file)));
            return 1;
        }
    }

    public static List<File> removeDuplicate(final List<File> files) {
        List<File> result = new ArrayList<File>(files);
        Iterator<File> iteratorFile = result.iterator();
        while (iteratorFile.hasNext()) {
            File file = iteratorFile.next();
            File parent = file.getParentFile();
            while (parent != null) {
                if (files.contains(parent)) {
                    iteratorFile.remove();
                    break;
                }
                parent = parent.getParentFile();
            }
        }
        return result;
    }

    public static File commonParent(final List<File> files) {
        List<File> possiblesParents = null;
        for (File file : files) {
            if (possiblesParents == null) {
                possiblesParents = new ArrayList<File>();
                File parent = file.getParentFile();
                while (parent != null) {
                    possiblesParents.add(parent);
                    parent = parent.getParentFile();
                }
            } else {
                File parent = file.getParentFile();
                while (parent != null) {
                    int indexOf = possiblesParents.indexOf(parent);
                    if (indexOf == -1) {
                        parent = parent.getParentFile();
                    } else {
                        for (int i = 0; i < indexOf; i++) {
                            possiblesParents.remove(0);
                        }
                        break;
                    }
                }
            }
        }
        if (possiblesParents.size() == 0) {
            return null;
        }
        return possiblesParents.get(0);
    }

    private File parent;

    @Override
    public OutputStream getOutputStream() throws IOException {
        if (sources.size() <= 0) {
            return null;
        }

        String name;
        parent = null;
        if (sources.size() == 1) {
            File source = sources.get(0);
            name = source.getName();
            parent = source.getParentFile();
        } else {
            sources = removeDuplicate(sources);
            parent = commonParent(sources);
            name = "Archive";
        }

        File zipFile = new File(parent, name + ".zip");
        int count = 2;
        while (zipFile.exists()) {
            zipFile = new File(parent, name + " " + count + ".zip");
            count++;
        }
        return new FileOutputStream(zipFile);
    }

    @Override
    public List<FutureEntry> getFutureEntries() throws IOException {
        List<FutureEntry> result = new ArrayList<FutureEntry>();
        for (File source : sources) {
            String prefix = "";
            File sourceParent = source.getParentFile();
            if (parent != null) {
                while (!sourceParent.equals(parent)) {
                    prefix = sourceParent.getName() + "/" + prefix;
                    sourceParent = sourceParent.getParentFile();
                }
            }
            addFileInArchive(source, prefix, result);
        }
        return result;
    }

}
